问题：
1.如何体现先加载AOF文件,再加载RDB文件
2.做以下操作，如果按照先读AOF，再读RDB规则的话，应该会有数据，可是没有。解析下为什么？
  写入数据----->save---->停服务----->备份AOF文件----->删除AOF文件---->起服务----->keys *
3.修复AOF文件后，数据是空的？

##################################################################################
NoSQL数据库管理
NSD NoSQL
DAY03
1.redis主从复制
1.1 配置主从、主从从、一主多从
1.2 哨兵模式

2.redis持久化
2.1 RDB
2.2 AOF

##################################################################################
Redis主从复制概述
●结构模式
   一主一从、一主多从、主从从
●工作原理
  &slave向master发送sync命令
  &master启动后台存盘进程,并收集所有修改数据命令
  &master完成后台存盘后,传送整个数据文件到slave
  &slave接收数据文件,加载到内存中完成首次完全同步
  &后续有新数据产生时,master继续将新的数据收集到的修改命令依次传给slave,完成同步
●缺点
  &网络繁忙,会产生数据同步延时问题    
  &系统繁忙,会产生数据同步延时问题  
  #因为从库同步主库需要执行master的数据文件，
  #如果因为网络问题或者服务器系统进程繁忙排队，那么文件传输就会有问题
##################################################################################
临时部署redis主从
●查看主从配置    info replication
●配置从库        slaveof 主库IP 端口
●还原从库        slaveof no one
################################################################################## 
部署Redis主从/一主多从
●配置从库
 +指定主库
   192.168.4.52:6352> slaveof 192.168.4.51 6351
   OK
 +查看主从状态
   192.168.4.52:6352> info replication
   # Replication
   role:slave
   master_host:192.168.4.51
   master_port:6351
 
●主库查看状态
  192.168.4.51:6351> info replication
  # Replication
  role:master
  connected_slaves:1
  slave0:ip=192.168.4.52,port=6352,state=online,offset=224,lag=0
  
●添加从库53
  192.168.4.53:6353> slaveof 192.168.4.51 6351
  OK
  192.168.4.53:6353> info replication
  # Replication
  role:slave
  master_host:192.168.4.51
  master_port:6351
  
##################################################################################
部部署Redis主从从
●保留51与52的主从配置

●把192.168.4.53还原为主库   
  192.168.4.53:6353> slaveof no one
  OK
●指定53的主库为52
  192.168.4.53:6353> slaveof 192.168.4.52 6352
  OK
  192.168.4.53:6353> info replication
  # Replication
  role:slave
  master_host:192.168.4.52
  master_port:6352
  slave_read_only:1          #从库为只读
##################################################################################

永久配置主从从
●主库
 +配置密码
  ~]# vim /etc/redis/6379.conf    #从库52，53都配置
  501 requirepass 123456
 +停服务
  ~]# /etc/init.d/redis_6379 stop
 +修改脚本
  ~]# vim /etc/init.d/redis_6379
  $CLIEXEC -p $REDISPORT -h 192.168.4.51 -a 123456 shutdown
 +起服务
  ~]# /etc/init.d/redis_6379 start 
  
●从库52
 +修改配置文件
  ~]# vim /etc/redis/6379.conf    #从库52配置
  282 slaveof 192.168.4.51 6351   #去掉注释
  289 masterauth 123456           #设置主库51访问密码
  501 requirepass 123456          #52作为53的主库，因此需要配置密码
 +停服务
  ~]# /etc/init.d/redis_6379 stop
 +修改脚本
  ~]# vim /etc/init.d/redis_6379
  $CLIEXEC -p $REDISPORT -h 192.168.4.52 -a 123456 shutdown 
 +起服务
  ~]# /etc/init.d/redis_6379 start 
  
●从库53
 +修改配置文件
  ~]# vim /etc/redis/6379.conf    #从库53配置
  282 slaveof 192.168.4.52 6352   #去掉注释
  289 masterauth 123456           #设置主库52访问密码
 +重启服务
  ~]# /etc/init.d/redis_6379 restart

##################################################################################  
哨兵模式(难点)
●哨兵模式
  主库宕机后,从库自动升级为主库
  有新的主库后，主配置文件指定主库一行回被删除。282行
##################################################################################
部署哨兵模式
主51 从52 从53(主是52)
在52上部署哨兵服务       #为了省机器
●修改配置文件sentinel.conf
 [root@redis52 ~]# vim /etc/sentinel.conf      #/etc/ 没有该文件
 sentinel monitor redis51 192.168.4.51 6351 1  #哨兵监视主库51
 sentinel auth-pass redis51 123456
   #sentinel monitor 主库主机名  主库IP  端端口  票数
   #sentinel auth-pass 主库主机名 主库密码
    #票数：主库宕机后, 票数大于1的主机被升级为主库；票数是哨兵服务器的投票
 
●启动哨兵程序 
 +用命令启动 redis-sentinel /etc/sentinel.conf
 
●测试哨兵服务
 +主库51停redis服务
 [root@redis51 ~]# /etc/init.d/redis_6379 stop
   Stopping ...
   Redis stopped
 +把51redis服务停止后，哨兵服务器52多出以下内容  
  [root@redis52 ~]# redis-sentinel /etc/sentinel.conf    
  4148:X 28 Sep 11:29:31.080 # +promoted-slave slave 192.168.4.52:6352 192.168.4.52 6352 @ redis51 192.168.4.51 6351
  4148:X 28 Sep 11:29:31.081 # +failover-state-reconf-slaves master redis51 192.168.4.51 6351
  4148:X 28 Sep 11:29:31.109 # +failover-end master redis51 192.168.4.51 6351
  4148:X 28 Sep 11:29:31.109 # +switch-master redis51 192.168.4.51 6351 192.168.4.52 6352
  4148:X 28 Sep 11:29:31.109 * +slave slave 192.168.4.51:6351 192.168.4.51 6351 @ redis51 192.168.4.52 6352
  4148:X 28 Sep 11:29:31.767 * +slave slave 192.168.4.53:6353 192.168.4.53 6353 @ redis51 192.168.4.52 6352
  4148:X 28 Sep 11:30:01.149 # +sdown slave 192.168.4.51:6351 192.168.4.51 6351 @ redis51 192.168.4.52 6352
 
 +以上信息时52成为新的主库
 +查看52的信息
  
################################################################################## 
●哨兵服务器会自动修改配置文件
 [root@redis52 ~]# cat /etc/sentinel.conf 
 sentinel myid 2390f8ee95a78c05d4c13dccb7bf3aaed89f9218
 sentinel monitor redis51 192.168.4.52 6352 1
 # Generated by CONFIG REWRITE
 port 26379
 dir "/root"
 sentinel auth-pass redis51 123456
 sentinel config-epoch redis51 1
 sentinel leader-epoch redis51 1
 sentinel known-slave redis51 192.168.4.51 6351
 sentinel known-slave redis51 192.168.4.53 6353
 sentinel current-epoch 1
##################################################################################
主从扩展
●生产中用得最多的是一主多从。
如果需要启用哨兵模式，
最好配置3台哨兵服务器，票数为2时，可以切换该机
所有的redis服务需要设置密码，并修改脚本

●配置文件：
vim /etc/sentinel.conf
sentinel monitor redis31 192.168.4.31 6331 2
sentinel auth-pass redis31 123456
bind 0.0.0.0    #监听任何地址,必须加上

##################################################################################
redis持久化-----------RDB
●方式1：RDB
 redis数据库文件,全称redis database  
 &数据持久化方式之一
 &按照指定时间间隔,将内存中的数据集快照写入硬盘；
 &存储的数据文件名默认为dump.rdb
 &术语叫Snapshot快照
 &恢复时,将快照文件直接读入内存
●使用RDB恢复数据的方法
  停值服务后，把备份的rdb文件拷贝会数据库目录后，再启动服务即可
##################################################################################
redis持久化-----------RDB
●相关配置参数
 vim /etc/redis/6379.conf
 <------------------------------------
 217 #   save ""    #禁用RDB
 219 save 900 1     #900秒内，有1个数据发生变化，就存储；以此类推
 220 save 300 10     
 221 save 60 10000
 254 dbfilename dump.rdb  #指定RDB数据库文件名
 
 242 rdbcompression yes   #是否启用数据压缩
 251 rdbchecksum yes
 236 stop-writes-on-bgsave-error yes
 ------------------------------------>
 
●手动保存数据
  save   #阻塞写存盘
  bgsave #不阻塞写存盘 
●压缩                                     #为了优化bgsave
  rdbcompression yes|no
●在存储快照后,使用crc16算法做数据校验 #为了优化bgsave
  rdbchecksum yes|no
● bgsave出错时停止写操作                #为了优化bgsave
  stop-writes-on-bgsave-error yes|no
##################################################################################

CPU工作原理
时间片；周期性执行每个进程
##################################################################################
redis持久化-----------RDB
RDB优点/缺点
●RDB优点
  &高性能的持久化实现 —— 创建一个子进程来执行持久化,
  先将数据写入临时文件,持久化过程结束后,
  再用这个临时文件替换上次持久化好的文件;
  过程中主进程不做任何IO操作，只负责客户端的请求。
  &比较适合大规模数据恢复,且对数据完整性要求不是非常高的场合
●RDB的缺点
  &意外宕机时,最后一次持久化的数据会丢

##################################################################################
redis持久化-----------RDB
案例2 :使用RDB文件恢复数据
要求如下:
– 启用RDB
– 设置存盘间隔为120秒 10个key改变存盘
– 备份RDB文件
– 删除数据
– 使用RDB文件恢复数据
##################################################################################
redis持久化-----------AOF
●方式2：   AOF  Append Only File
   &记录在redis服务器所有的写操作
   &不断将新的写操作追加到文件的末尾
  &cat可以查看
   &默认没有启用
##################################################################################  
redis持久化-----------AOF
●相关配置参数
 +文件名
  677 appendfilename  “appendonly.aof”   #指定文件名
  673 appendonly yes    #启用aof，默认no  
 +AOF文件记录写操作的方式
  702 # appendfsync always   #有新的写操作就记录，常用
  703 appendfsync everysec   #每秒记录一次，默认的，常用
  704 # appendfsync no       #从不记录
  • 日志文件会不断增大,何时触发日志重写?
  – redis会记录上次重写时AOF文件的大小
  – 默认配置当aof文件是上次rewrite后大小的1倍且文件大于64M时触发
  > auto-aof-rewrite-percentage 100
  > auto-aof-rewrite-min-size 64mb

●启用aof后(改配置,起服务)
  ~]# ls /var/lib/redis/6379/
  appendonly.aof  dump.rdb
●写数据，查看aof文件
  cat /var/lib/redis/6379/appendonly.aof
##################################################################################
redis持久化-----------AOF
●修复AOF文件
  redis-check-aof --fix /var/lib/redis/6379/appendonly.aof
  #修复后没有数据了
  
●AOF与RDB同时存在时 
 加载redis服务时
 先读AOF文件，再读RDB文件 
●flushall后修复数据
 ~]# sed -i '/flushall/d' /var/lib/redis/6379/appendonly.aof

●命令行启用AOF
  > config set appendonly yes
  > info  #查看redis服务器所有配置 
  
●生产环境中临时需要启用AOF(配置)-------------------重要
  步骤1：备份/var/lib/redis/6379/dump.rdb 
  步骤2：停服务
  步骤3：修改配置文件，启用AOF #如何启用参照上述
  步骤4：起服务 
    redis-server /etc/redis/6379.conf --appendonly no  #不要用脚本
  步骤5：命令行启动AOF
    > config set appendonly yes
  步骤6：重写AOF文件  
    >：bgrewriteaof      #把RDB文件的数据读到AOF文件中
  步骤7：重启服务
##################################################################################

数据类型
string
hash
list
set
zset
##################################################################################
string
●字符串操作
 +赋值：
   set key value [EX seconds] [PX milliseconds] [NX|XX]
   #[EX seconds],以秒为单位设置有效期
   #[PX milliseconds],以毫秒为单为设置有效期
   #[NX|XX]；nx:变量存在时,不赋值。 xx:变量存在时,赋值。
 +变量值修改
  setrange key offset value #从偏移量开始复写key的特定位的值,
 +统计字符串长度 
  strlen key
 +位操作
  setbit key offset 0|1     #变量的某个位，变为1
  bitcount key              #计算bit=1的数量
 +自减/自加
  decr key
  decrby key decrement
  incr key
  incrby key increment
 +取值
  get key
   &返回key存储的字符串值,若key不存在则返回null
   &若key的值不是字串,则返回错误,get只能处理字串
 +按位置取值
  getrange key start end
   &返回字串值中的子字串,截取范围为start和end
   &负数偏移量表示从末尾开始计数,-1表示最后一个字符,-2表示倒数第二个字符
 +批量赋值/取值
  mset key1 value1 key2 value2 .... 
  mget key1 key2
●例子需要补充
 +set 
   > set nsd 777 ex  12 nx  #12秒有效期,变量nsd存在时,不赋值
   
 +SETRANGE
  > set pass 123456789
  > get pass
  "123456789"
  > SETRANGE pass 4 *****   #从第4位开始修改
  (integer) 9
  > get pass
  "1234*****"
  
 +strlen
  > strlen pass
  (integer) 9
 +bicount

##################################################################################
List列表简介
  &Redis的list是一个字符队列
   &先进后出,位置从后开始数，0起始
   &一个key可以有多个值

List列表操作
• lpush key value [value...]
   &将一个或多个值value插入到列表key的表头
  &Key不存在,则创建key
   > lpush list a b c  //list1值依次为c、b、a

• lrange key start stop
  &从开始位置读取key的值到stop结束
   > lrange list 0 2   //从0位开始,读到2位为止
   > lrange list 0 -1  //从开始读到结束为止
   > lrange list 0 -2  //从开始读到倒数第2位为止
• lpop key
  &移除并返回列表头元素数据,key不存在则返回nil
   > lpop yyy
• llen key
  &返回列表key的长度
• lindex key index
  &返回列表中第index个值
  > lindex key 0 ; lindex key 2; lindex key -2
• lset key index value
  &将key中index位置的值修改为value
  > lset list 3 test #将list中第3个值修改为test
• rpush key value [value...]
  &将value插入到key的末尾
   > rpush list3 a b c  #从-1位开始插入数据
   > rpush list3 d      #末尾插入d
• rpop key
  &删除并返回key末尾的值    
  > rpop list4          #删除末尾的c,并返回删除的值
##################################################################################
Hash表
  &是一个string类型的field和value的映射表
  &一个key可对应多个field,一个field对应一个value   #记这个
  &将一个对象存储为hash类型,较于每个字段都存储成string类型更能节省内存
• hset
   &给hash表单个列赋值 
  hset key field value
  > hset book version 2.0
• hget 
   &对hash表单个列取值
  > hget book date 
• hgetall
   &返回hash表中所有field的值  #奇数行位列名，偶数行位值
• hvals
   & 返回hash表中所有field的值 
  > hvals book
• hmset
   &对hash表多个列取值
  hmset key field value [field value ...]  
  > hmset book pages 50 cbs rmrb  
• hkeys
  &返回hash表中所有field名称  
  hkeys key
  > hvals book
• hmget 
  hmget key field [field...]
  &返回hash表中多个field的值
  > hmget site google baidu  
• hdel 
  hdel key field [field...]
  &删除hash表中多个field的值,不存在则忽略
  > hdel site google baidu

+例子
> hset book author dmy
> hset book version 2.0
> hset booke title opezd
> hset book title opezd
> hset book date 2018-09-29
> hget book date    #取值----book变量的date
> HGETALL book  #列出所有字段及它的值
 1) "author"
 2) "dmy"
 3) "version"
 4) "2.0"
 5) "title"
 6) "opezd"
 7) "date"
 8) "2018-09-29"
 9) "pages"
 10) "50"
 11) "cbs"
 12) "rmrb"
> hkeys book     #所有字段
1) "author"
2) "version"
3) "title"
4) "date"
5) "pages"
6) "cbs" 
> hvals book
1) "dmy"
2) "2.0"
3) "opezd"
4) "2018-09-29"
5) "50"
6) "rmrb"
















